# yamllint disable rule:line-length
# yamllint disable rule:comments
# too many spelling things, spell-checker: disable
---
name: Build executables or extension modules from Python projects

branding:
  icon: "package"
  color: "blue"

description: "Build a modules or standalone executable from python code using Nuitka on Mac/Linux/Windows. Very wide range of compatibility."

inputs:
  working-directory:
    default: "."
    description: "Directory to run nuitka in if not top level"

  nuitka-version:
    default: "main"
    description: "Version of nuitka to use, branches, tags work"

  ### Only Required Input ###
  script-name:
    required: true
    description: "Path to python script that is to be built."

  # Enable Nuitka Commercial features of Nuitka using a PAT (personal access token)
  access-token:
    description: "Github personal access token of an account authorized to access the Nuitka-commercial repo"

  ### Nuitka Modes ###
{{ get_top_options() }}

  ### Nuitka Plugins to enable. ###
{{ get_group_options("Plugin control") }}

  ### Include Qt Plugins. ###
  include-qt-plugins:
    description: "A comma separated list of Qt plugins, such as qml, etc."
  noinclude-qt-plugins:
    description: "A comma separated list of Qt plugins to not included, to take away from default."

  ### Nuitka Tracing/Reporting features
{{ get_group_options("Tracing features") }}

  ### Control the inclusion of data files in result. ###
{{ get_group_options("Data files") }}

  ### Control the inclusion of modules and packages in result. ###
  include-package:
    description: 'Include a whole package. Give as a Python namespace, e.g. "some_package.sub_package" and Nuitka will then find it and include it and all the modules found below that disk location in the binary or extension module it creates, and make it available for import by the code. To avoid unwanted sub packages, e.g. tests you can e.g. do this "--nofollow-import-to=*.tests". Default empty.'
  include-module:
    description: 'Include a single module. Give as a Python namespace, e.g. "some_package.some_module" and Nuitka will then find it and include it in the binary or extension module it creates, and make it available for import by the code. Default empty.'
  include-plugin-directory:
    description: "Include the content of that directory, no matter if it is used by the given main program in a visible form. Overrides all other inclusion options. Can be given multiple times. Default empty."
  include-plugin-files:
    description: "Include into files matching the PATTERN. Overrides all other follow options. Can be given multiple times. Default empty."
  prefer-source-code:
    description: "For already compiled extension modules, where there is both a source file and an extension module, normally the extension module is used, but it should be better to compile the module from available source code for best performance. If not desired, there is --no- prefer-source-code to disable warnings about it. Default off."
  nofollow-import-to:
    description: "Do not follow to that module name even if used, or if a package name, to the whole package in any case, overrides all other options. Can be given multiple times. Default empty."
  user-package-configuration-file:
    description: "User provided YAML file with package configuration. You can include DLLs, remove bloat, add hidden dependencies. Check User Manual for a complete description of the format to use. Can be given multiple times. Defaults to empty."

  ### Onefile behavior details ###
  onefile-tempdir-spec:
    description: "Use this as a folder to unpack onefile. Defaults to '%TEMP%\\onefile_%PID%_%TIME%', but e.g. '%CACHE_DIR%/%COMPANY%/%PRODUCT%/%VERSION%' would be cached and good too."
  onefile-child-grace-time:
    description: "When stopping the child, e.g. due to CTRL-C or shutdown, how much time to allow before killing it the hard way. Unit is ms. Default 5000."
  onefile-no-compression:
    description: "When creating the onefile, disable compression of the payload. Default is false."

{{ get_group_options("Control the warnings to be given by Nuitka") }}

  ### Deployment modes ###
{{ get_group_options("Deployment control") }}

  ### Output choices ##
  output-dir:
    description: "Directory for output builds"
    default: build
  output-file:
    description: "Specify how the executable should be named. For extension modules there is no choice, also not for standalone mode and using it will be an error. This may include path information that needs to exist though. Defaults to '<program_name>' on this platform. .exe)"

  ### Console handling ###
  disable-console:
    description: "When compiling for Windows or macOS, disable the console window and create a GUI application. Defaults to false."
  enable-console:
    description: "When compiling for Windows or macOS, enable the console window and create a GUI application. Defaults to false and tells Nuitka your choice is intentional."

  ### Version information ###
{{ get_group_options("Binary Version Information") }}

  ### Windows specific controls ###
{{ get_group_options("Windows specific controls") }}

  ### macOS specific controls: ###
{{ get_group_options("macOS specific controls") }}

  ### Linux specific controls: ###
{{ get_group_options("Linux specific controls") }}

  ### data file embedding (commercial only) ###
  embed-data-files-compile-time-pattern:
    description: Pattern of data files to embed for use during compile time. These should match target filenames.
  embed-data-files-run-time-pattern:
    description: Pattern of data files to embed for use during run time. These should match target filenames.
  embed-data-files-qt-resource-pattern:
    description: Pattern of data files to embed for use with Qt at run time. These should match target filenames.
  embed-debug-qt-resources:
    description: For debugging purposes, print out information for Qt resources not found.

  ### traceback encryption (commercial only) ###
  encryption-key:
    description: "The key to use."
  encrypt-stdout:
    description: "Apply encryption to standard output."
  encrypt-stderr:
    description: "Apply encryption to standard error."

  ### Backend C compiler choices. ###
{{ get_group_options("Backend C compiler choice") }}

  ### Debug features ###
{{ get_group_options("Debug features") }}


  ### action controls: ###
  disable-cache:
    description: "Disables caching of compiled binaries. Defaults to false."

{% raw %}
runs:
  using: "composite"
  steps:
    - name: Setup Environment Variables
      if: ${{ !inputs.disable-cache }}
      shell: bash
      run: |
        echo "NUITKA_CACHE_DIR=${{ github.action_path }}/nuitka/cache" >> $GITHUB_ENV
        echo "PYTHON_VERSION=$(python --version | awk '{print $2}' | cut -d '.' -f 1,2)" >> $GITHUB_ENV
    - name: Install Dependencies
      shell: bash
      run: |
        pip install -r "${{ github.action_path }}/requirements.txt"

        # With commercial access token, use that repository.
        if [ "${{ inputs.access-token }}" != "" ]; then
          repo_url="git+https://${{ inputs.access-token }}@github.com/Nuitka/Nuitka-commercial.git"
        else
          repo_url="git+https://$@github.com/Nuitka/Nuitka.git"
        fi

        pip install "${repo_url}/@${{inputs.nuitka-version }}#egg=nuitka"
    - name: Install ccache
      # TODO: Proper "in" test could make sense here.
      if: ${{ inputs.disable-cache != 'ccache' && runner.os == 'Linux' }}
      shell: bash
      run: |
        sudo apt-get install -y ccache
    - name: Cache Nuitka cache directory
      if: ${{ !inputs.disable-cache }}
      uses: actions/cache@v4
      with:
        path: ${{ env.NUITKA_CACHE_DIR }}
        key: ${{ runner.os }}-python-${{ env.PYTHON_VERSION }}-nuitka-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-python-${{ env.PYTHON_VERSION }}-
          ${{ runner.os }}-python-
          ${{ runner.os }}-

    - name: Build with Nuitka
      env:
        NUITKA_WORKFLOW_INPUTS: ${{ toJson(inputs) }}
      shell: bash
      run: |
        set -e
        python -m nuitka --github-workflow-options
      working-directory: ${{ inputs.working-directory }}
{% endraw %}